﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using Autofac;
using Nancy;
using QQ2564874169.Core.Utils;
using QQ2564874169.WebFx.Nancy.Responses;
using QQ2564874169.WebFx.Nancy.Web;

namespace QQ2564874169.WebFx.Nancy
{
    public static class NancyExts
    {
        /// <summary>
        /// 通过参数名称获得Query或者Form中的参数值
        /// </summary>
        public static string Params(this NancyController controller, string name)
        {
            return controller.QueryParams(name) ??
                   controller.FormParams(name) ??
                   controller.RouteParam(name);
        }

        /// <summary>
        /// 通过参数名称获得Query中的参数值
        /// </summary>
        public static string QueryParams(this NancyController controller, string name)
        {
            var dict = controller.Request.Query as DynamicDictionary;
            if (dict != null && dict.ContainsKey(name))
            {
                return dict[name].ToString();
            }
            return null;
        }

        /// <summary>
        /// 通过参数名称获得Form中的参数值
        /// </summary>
        public static string FormParams(this NancyController controller, string name)
        {
            var dict = controller.Request.Form as DynamicDictionary;
            if (dict != null && dict.ContainsKey(name))
            {
                return dict[name].ToString();
            }
            return null;
        }

        /// <summary>
        /// 获取URL中的Route值
        /// </summary>
        public static string RouteParam(this NancyController controller, string name)
        {
            var dict = controller.Context.Parameters as DynamicDictionary;
            if (dict != null && dict.ContainsKey(name))
            {
                return dict[name].ToString();
            }
            return null;
        }

        public static ExcelResponse AsExcel(this IResponseFormatter formatter,
            string fileName, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> rows,
            Encoding encoding = null)
        {
            var dt = new DataTable();
            foreach (var column in columns)
            {
                dt.Columns.Add(column);
            }
            foreach (var row in rows)
            {
                var items = row as string[] ?? row.ToArray();
                if (items.Length != dt.Columns.Count)
                    throw new ArgumentOutOfRangeException("行中的列数量必须和列的标题一致。");
                var dr = dt.NewRow();
                for (var i = 0; i < items.Length; i++)
                {
                    dr[i] = items[i];
                }
                dt.Rows.Add(dr);
            }
            var res = new ExcelResponse(fileName, dt);

            if (encoding != null)
            {
                res.ContentEncoding = encoding;
            }
            return res;
        }

        public static ExcelResponse AsExcel(this IResponseFormatter formatter,
            string fileName, IEnumerable<object> data,
            Encoding encoding = null)
        {
            var rows = data as object[] ?? data.ToArray();
            if (!rows.Any()) return new ExcelResponse(fileName);

            var t = rows.First().GetType();
            var ps = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var titles = ps.Select(item => item.Name);
            var content = rows.Select(row => ps.Select(p => (p.GetValue(row) ?? "").ToString()).ToArray());
            return formatter.AsExcel(fileName, titles, content, encoding);
        }

        public static JsonResponse NewAsJson(this IResponseFormatter formatter, object model, Encoding encoding = null)
        {
            return new JsonResponse(model, encoding);
        }

        internal static IComponentContext Update(this IComponentContext container, Action<ContainerBuilder> register)
        {
            var builder = new ContainerBuilder();
            register(builder);
            builder.Update(container.ComponentRegistry);
            return container;
        }

        public static T QQBind<T>(this NancyController module)
        {
            var ps = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var obj = Activator.CreateInstance<T>();
            foreach (var p in ps)
            {
                if (p.CanWrite == false)
                    continue;
                var value = module.Params(p.Name);
                var pt = p.PropertyType;
                if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    pt = pt.GetGenericArguments().First();
                }
                if (string.IsNullOrEmpty(value) == false)
                {
                    var pv = p.PropertyType.IsEnum ? Enum.Parse(pt, value) : Convert.ChangeType(value, pt);
                    p.SetValue(obj, pv);
                }
            }
            return obj;
        }

        public static string GetClientIp(this Request request)
        {
            var ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrWhiteSpace(ip))
            {
                ip = request.UserHostAddress;
            }
            else if (ip.Contains(","))
            {
                ip = ip.Split(',').First().Trim();
            }
            return ip;
        }
    }
}
